# pyjbot/jabberbot.py
#
#

""" jabber bot definition """

__copyright__ = 'this file is in the public domain'
__revision__ = '$Id: bot.py 75 2005-09-12 16:33:00Z bart $'

from gozerbot.commands import cmnds
from gozerbot.users import users
from gozerbot.redispatcher import rebefore, reafter
from gozerbot.callbacks import callbacks
from gozerbot.monitor import jabbermonitor
from gozerbot.wait import Jabberwait
from gozerbot.generic import rlog, handle_exception
from gozerbot.config import config
from gozerbot.plugins import plugins
from gozerbot.eventhandler import Commandhandler
import gozerbot.thr as thr
import jabber, xmlstream, time, Queue, copy

class Jabbermsg(jabber.Message):

    def __init__(self, msg):
        jabber.Message.__init__(self, frm=str(msg.getFrom()), \
to=msg.getTo(), body=msg.getBody(), type=msg.getType())

    def reply(self, txt):
        """ reply to msg of groupchat """
        repl = self.buildReply(txt)
        if self.groupchat:
            if self.resource == self.bot.nick:
                return
            repl.setFrom(self.bot.me)
            repl.setTo(self.channel)
            repl.setType('groupchat')
        self.bot.send(repl)

    def toirc(self, bot):
        self.cmnd = 'JABBER'
        self.prefix = ""
        self.postfix = ""
        self.nick = 'JABBER'
        self.ruserhost = str(self.getFrom())
        self.userhost = self.ruserhost
        self.resource = self.getFrom().getResource()
        self.channel = self.getFrom().getStripped()
        self.txt = self.getBody()
        self.origtxt = self.txt
        self.to = str(self.getTo())
        self.time = time.time()
        self.msg = None
        self.args = self.txt.split()[1:]
        self.rest = ' '.join(self.args)
        self.usercmnd = 0
        self.bot = bot
        self.sock = None
        self.queues = []
        self.printto = self.getFrom()
        self.speed = 5
        self.groupchat = 0
        return self

    def missing(self, txt):
        if self.origtxt:
            self.reply(self.origtxt.split()[0] + ' ' + txt)
        else:
            self.reply('missing origtxt: %s' % txt)

class Bot(jabber.Client):

    """ jabber bot class """

    def __init__(self, host, username, password, port=5347, ssl=0):
        self.name = 'main'
        self.sock = None
        self.starttime = time.time()
        self.owner = config['jabberowner']
        # see if owner already has a user account if not merge otherwise add
        try:
            name = users.getname(self.owner)
            if not name:
                merged = users.merge('owner', self.owner)
                if not merged:
                    users.add('owner', [self.owner], perms = ['USER', 'OPER'])
        except:
            handle_exception()
        self.host = host
        self.username = username
        self.me = "%s@%s" % (username, host)
        self.nick = self.username
        self.password = password
        self.cc = config['jabbercc']
        if not ssl:
            jabber.Client.__init__(self, host, port)
        else:
            jabber.Client.__init__(self, host, port, connection=xmlstream.TCP_SSL)
        self.users = users
        self.test = 0
        self.stopped = 0
        self.registerHandler('message', self.messageHandler)
        self.registerHandler('presence', self.presenceHandler)
        self.commandhandler = Commandhandler()
        self.joinedchannels = []
        self.state = {}
        self.channels = None
        self.backlog = []
        self.userhosts = {}
        self.privwait = Jabberwait()

    def doprocess(self):
        """ process loop """
        while not self.stopped:
            try:
                time.sleep(0.1)
                self.process()
            except:
                handle_exception()
                rlog(100, 'bot', 'exception occured .. stopping process \
loop')
                return

    def dispatch(self, stanza):
        """ add callback on stanza """
        rlog(1, '%s-in' % self.username, unicode(stanza))
        stanza.cmnd = 'JABBER'
        jabber.Client.dispatch(self, stanza)
        callbacks.check(self, stanza)

    def doconnect(self):
        """ connect to server .. start read loop """
        rlog(10, self.username, 'connecting to %s' % self.host)
        try:
            self.connect()
        except:
            handle_exception()
            rlog(10, self.username, "can't connect to %s" % self.host)
            return
        rlog(10, self.username, 'doing auth')
        if not self.auth(self.username, self.password, 'pyjbot'):
            rlog(10, self.username, 'auth failed .. registering %s' % self.username)
            self.setRegInfo('username', self.username)
            self.setRegInfo('password', self.password)
            if not self.sendRegInfo():
                rlog(100, self.username, 'registration failed')
                return
            rlog(10, self.username, 'registration ok')
            if not self.auth(self.username, self.password, 'pyjbot'):
                rlog(10, self.username, 'auth failed')
                return
        rlog(100, self.username, 'connected!')
        self.requestRoster()
        self.send(jabber.Presence(status="Online", priority="4"))
        self.stopped = 0
        thr.start_new_thread(self.doprocess, ())
        return 1

    def messageHandler(self, conn, msg):
        """ message handler """
        if self.test:
            return
        m = Jabbermsg(msg)
        jmsg = m.toirc(self)
        if self.privwait.check(jmsg):
            return
        if jmsg.getType() == 'groupchat':
            jmsg.groupchat = 1
        else:
            jmsg.groupchat = 0
        if self.me in jmsg.userhost:
            return 0
        go = 0
        try:
            cc = bot.channels[jmsg.channel]['cc']
        except:
            cc = '!'
        if jmsg.groupchat and jmsg.txt[0] == cc:
            jmsg.txt = jmsg.txt[1:]
            go = 1
        elif not jmsg.groupchat:
            go = 1
        if go:
            try:
                plugins.trydispatch(conn, jmsg)
            except:
                handle_exception()

    def presenceHandler(self, conn, pres):
        """ overloaded presence handler """
        type = pres.getType()
        if type == 'subscribe':
            fromm = pres.getFrom()
            self.send(jabber.Presence(to=fromm, type='subscribed'))
            self.send(jabber.Presence(to=fromm, type='subscribe'))

    def disconnectHandler(self, conn):
        """ overloaded disconnect handler """
        self.stopped = 1
        rlog(100, self.username, "disconnected")

    def send(self, what):
        """ send via jabber.Client and check for output monitor """
        if self.stopped:
            return
        jabber.Client.send(self, what)
        #jabbermonitor.check(what)
        rlog(1, '%s-send' % self.username, str(what))

    def say(self, printto, txt):
        """ say txt to printto """
        message = jabber.Message(frm=self.me, to=printto, body=txt)
        self.send(message)
        return message

    def wait(self, msg, txt):
        """ wait for user response """
        self.reply(msg, txt)
        queue = Queue.Queue()
        wait.register(msg, queue)
        result = queue.get()
        if result:
            return result.getBody()

    def exit(self):
        pass

    def join(self, channel, password=None):
        if not self.channels.has_key(channel):
            # init channel data
            self.channels.setdefault(channel, {})
        chan = self.channels[channel]
        # if password is provided set it
        if password:
            chan['key'] = password
        # check for control char .. if its not there init to !
        if not chan.has_key('cc'):
            chan['cc'] = '!'
        # do the actual join
        presence = jabber.Presence(to=channel + '/' + self.nick)
        presence.setFrom(self.me)
        self.send(presence)

    def part(self, channel):
        presence = jabber.Presence(to=channel)
        presence.setFrom(self.me)
        presence.setType('unavailable')
        self.send(presence)
